package leetcode.f1t100;

import java.util.*;

/**
 * 给一个数组和目标值, 得出四叔相加等于目标值的组合
 * https://leetcode.com/problems/4sum/
 *
 * @Author lichongxiao
 * @Date 2022/9/29 19:25
 */
public class Q18_4Sum {
    public static void main(String[] args) {
        List<List<Integer>> ansList1 = new Q18_4Sum().fourSum1(new int[]{1, 0, -1, 0, -2, 2}, 0);
        List<List<Integer>> ansList = new Q18_4Sum().fourSum(new int[]{1, 0, -1, 0, -2, 2}, 0);
        for (List<Integer> ans : ansList1) {
            for (Integer i : ans) {
                System.out.print(i + " ");
            }
            System.out.println();
        }
        System.out.println();
        for (List<Integer> ans : ansList) {
            for (Integer i : ans) {
                System.out.print(i + " ");
            }
            System.out.println();
        }
    }

    /**
     * low level
     *
     * @param nums
     * @param target
     * @return
     */
    public List<List<Integer>> fourSum1(int[] nums, int target) {
        Arrays.sort(nums);
        List<List<Integer>> ansList = new ArrayList<>();
        int length = nums.length;
        for (int i = 0; i < length - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            for (int j = i + 1; j < length - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                for (int k = j + 1; k < length - 1; k++) {
                    if (k > j + 1 && nums[k] == nums[k - 1]) {
                        continue;
                    }
                    for (int l = length - 1; l > k; l--) {
                        long sum = (long) nums[i] + nums[j] + nums[k] + nums[l];
                        if (sum - target == 0) {
                            List<Integer> ans = new ArrayList<>();
                            ans.add(nums[i]);
                            ans.add(nums[j]);
                            ans.add(nums[k]);
                            ans.add(nums[l]);
                            ansList.add(ans);
                            break;
                        }
                    }
                }
            }
        }
        return ansList;
    }

    public List<List<Integer>> fourSum(int[] nums, int target) {
        int N = 4;
        Arrays.sort(nums);
        return sumN(nums, target, N, 0);
    }

    private List<List<Integer>> sumN(int[] nums, long target, int n, int index) {
        List<List<Integer>> ansList = new ArrayList<>();
        if (index >= nums.length - n + 1) {
            return ansList;
        }
        if (n == 2) {
            int left = index, right = nums.length - 1;
            while (left < right) {
                if (nums[left] == target - nums[right]) {
                    List<Integer> ans = new ArrayList<>();
                    ans.add(nums[left]);
                    ans.add(nums[right]);
                    ansList.add(ans);
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }

                    left++;
                    right--;
                } else if (nums[left] > target - nums[right]) {
                    right--;
                } else {
                    left++;
                }
            }
        } else {
            for (int i = index; i < nums.length - n + 1; i++) {
                List<List<Integer>> tempAnsList = sumN(nums, target - nums[i], n - 1, i + 1);
                if (tempAnsList != null && tempAnsList.size() > 0) {
                    for (List<Integer> tempAns : tempAnsList) {
                        tempAns.add(0, nums[i]);
                    }
                    ansList.addAll(tempAnsList);
                    while (i < nums.length - n + 1 && nums[i] == nums[i + 1]) {
                        i++;
                    }
                }
            }
        }
        return ansList;
    }
}
